﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using DimensionsHelper.Common.Contracts.Metadata;
using DimensionsHelper.Common.Metadata.Script;
#if !NET8_0_OR_GREATER
using DimensionsHelper.Common.Utils;
#else
using System.Diagnostics.CodeAnalysis;
#endif

namespace DimensionsHelper.Services.SQL;

/// <summary>
///     向SampleDataTable中添加分类值时使用的字段信息。
/// </summary>
public struct SampleValueInfo
{
    /// <summary>
    ///     样本的字段名。
    /// </summary>
    public string Field;

    /// <summary>
    ///     样本的字段值，分类值允许同时有多个值。
    /// </summary>
    public List<string> OriginalValues;
}


/// <summary>
///     当格式化SQL脚本并使用回调函数格式化时，使用的回调参数。
/// </summary>
public class SqlFormatEventArgs(string format, IList<SqlMetadataProvider.Storage> values) : EventArgs
{
    /// <summary>
    ///     当前使用的格式化模板字符串。
    /// </summary>
    public string Format { get; } = format;

    /// <summary>
    ///     已存储的字段数据列表。
    /// </summary>
    public IList<SqlMetadataProvider.Storage> Values { get; } = values;

    /// <summary>
    ///     格式化的结果，在订阅事件的对象内完成格式化后，应当将格式化的结果赋值给此属性。
    /// </summary>
    public string FormatResult { get; set; } = string.Empty;
}


/// <summary>
///     SQL脚本元数据存储类。对于内部值，只区分是否是Categorical类型的分类值。
///     针对分类值，在添加新值时，会先判定是否已经存在此分类值，不会重复添加。
/// </summary>
public class SqlMetadataProvider : MetadataProvider, IEnumerable<SqlMetadataProvider.Record>
{
    private const string DefaultKeyFieldName = "__PRIMARY_KEY__";
    private readonly Dictionary<string, List<string>> _defCache = new();


    private readonly IMetadataDocument _document;
    private readonly Record _dummyRecord;
    private readonly Dictionary<string, Record> _records;
    private int _version;
    private readonly string _sqlFormat;

    internal SqlMetadataProvider(IMetadataDocument document, string format)
    {
        _records = new Dictionary<string, Record>();
        _document = document;
        _sqlFormat = format;
        _dummyRecord = new Record(GetKeyFieldName(), "");
        _version = 1;
        Count = 0;
    }

    /// <summary>
    ///     以存储的记录条目数量。
    /// </summary>
    public int Count { get; private set; }


    /// <summary>
    ///     关键字字段名，可以忽略，如果不配置，将使用递增的条目编号作为关键字的值。
    /// </summary>
    public string? KeyFieldName { get; set; }

    /// <summary>
    ///     第一条记录。
    /// </summary>
    public Record? FirstRecord => _dummyRecord.NextRecord != _dummyRecord ? _dummyRecord.NextRecord : null;

    /// <summary>
    ///     最后一条样本记录。
    /// </summary>
    public Record? LastRecord => _dummyRecord.PreviousRecord != _dummyRecord ? _dummyRecord.PreviousRecord : null;

    /// <summary>
    ///     在<see cref="PopSqlScript" />格式化SQL脚本时优先使用的回调。
    /// </summary>
    public event EventHandler<SqlFormatEventArgs>? SqlFormatting;

    private string GetKeyFieldName() => string.IsNullOrEmpty(KeyFieldName) ? DefaultKeyFieldName : KeyFieldName!;


    /// <summary>
    ///     获取最后一条记录，LastRecord不是null，直接返回LastRecord，否则，创建一个新的Record、将其设置成LastRecord并返回。
    /// </summary>
    /// <param name="keyValue"></param>
    /// <returns></returns>
    public Record GetLastRecord(string keyValue = "")
    {
        if (_dummyRecord.PreviousRecord != _dummyRecord)
        {
            return _dummyRecord.PreviousRecord;
        }

        Record rec = new(GetKeyFieldName(),
            string.IsNullOrEmpty(keyValue) ? _version.ToString() : keyValue); // version在修改集合时会一直递增
        PushRecord(rec);
        return rec;
    }


    private void PushRecord(Record record)
    {
        Record last = _dummyRecord.PreviousRecord;

        _dummyRecord.PreviousRecord = record;
        last.NextRecord = record;

        record.PreviousRecord = last;
        record.NextRecord = _dummyRecord;

        _version++;
        Count++;

        string lowerKey = record.KeyValue.ToLower();
        if (!_records.TryAdd(lowerKey, record))
        {
            _records[lowerKey] = record;
        }
    }


    private void DeleteRecord(Record record)
    {
        if (record == _dummyRecord)
        {
            return;
        }

        _records.Remove(record.KeyValue.ToLower());

        Record prev = record.PreviousRecord;
        Record next = record.NextRecord;

        next.PreviousRecord = prev;
        prev.NextRecord = next;

        _version++;
        Count--;
    }


    /// <summary>
    ///     使用关键字查找记录条目，如果不存在，将创建一个新的并添加到集合末尾。
    /// </summary>
    /// <param name="key">记录关键字，不区分大小写。</param>
    public Record GetRecord(string key)
    {
        string lower = key.ToLower();

        if (_records.TryGetValue(lower, out var rec))
        {
            return rec;
        }

        rec = new Record(GetKeyFieldName(), key);
        PushRecord(rec);

        return rec;
    }


    /// <summary>
    ///     使用不定数量的关键字查找记录条目，关键字顺序将影响查找结果。如果不存在，将创建一个新的并添加到集合末尾。
    /// </summary>
    /// <param name="keys">记录关键字，不区分大小写。</param>
    public Record GetRecord(params string[] keys) => GetRecord(string.Join(",", keys));


    /// <summary>
    ///     移除指定关键字的记录条目。
    /// </summary>
    /// <param name="key"></param>
    public void Remove(string key)
    {
        if (_records.TryGetValue(key.ToLower(), out var rec))
        {
            DeleteRecord(rec);
        }
    }


    /// <summary>
    ///     移除包含不定数量关键字的记录条目。
    /// </summary>
    /// <param name="keys"></param>
    public void Remove(params string[] keys) => Remove(string.Join(",", keys));


    /// <summary>
    ///     清空所有以存储的数据。
    /// </summary>
    public void Clear()
    {
        _dummyRecord.NextRecord = _dummyRecord;
        _dummyRecord.PreviousRecord = _dummyRecord;

        _records.Clear();
        _defCache.Clear();

        _version++;
        Count = 0;
    }


    /// <summary>
    ///     将当前读取的最后一条记录格式化成SQL脚本，并移除该条记录。
    /// </summary>
    /// <returns></returns>
    public string PopSqlScript()
    {
        if (_dummyRecord.PreviousRecord == _dummyRecord)
        {
            return string.Empty;
        }

        string res;

        if (SqlFormatting != null)
        {
            SqlFormatEventArgs args = new SqlFormatEventArgs(_sqlFormat, _dummyRecord.PreviousRecord.Values);
            SqlFormatting.Invoke(this, args);
            res = args.FormatResult;
        }
        else
        {
            StringBuilder fieldNames = new StringBuilder();
            StringBuilder fieldValues = new StringBuilder();

            foreach (Storage val in _dummyRecord.PreviousRecord.Values)
            {
                if (fieldNames.Length > 0)
                {
                    fieldNames.Append(", ");
                }

                fieldNames.Append(val.FieldName);

                if (fieldValues.Length > 0)
                {
                    fieldValues.Append(", ");
                }

                fieldValues.Append(val.FieldValue);
            }

            res = string.Format(_sqlFormat, fieldNames, fieldValues);
        }

        _records.Remove(_dummyRecord.PreviousRecord.KeyValue.ToLower());
        DeleteRecord(_dummyRecord.PreviousRecord);

        return res;
    }


    public override IList<string> FetchCategoriesDefinition(string fieldName)
    {
        string cacheKey = fieldName.Replace(" ", "").ToLower();

        if (_defCache.TryGetValue(cacheKey, out var defs))
        {
            return defs;
        }

        string formatted = Regex.Replace(fieldName, @"\[\{.*?\}\]", "");
        string[] levels = formatted.Split('.');
        List<string> categories = [];

        if (levels.Length > 0)
        {
            var field =
                _document.Fields.Find<IField>(f => f.Name.Equals(levels[0], StringComparison.OrdinalIgnoreCase));

            int i = 1;
            while (field != null && i < levels.Length)
            {
                IFields fields;
                switch (field)
                {
                    case IBlock block:
                        fields = block.Fields;
                        break;
                    case IArray array:
                        fields = array.Class.Fields;
                        break;
                    default:
                        throw new Exception($"字段'{fieldName}'无效。");
                }

                string level = levels[i];
                field = fields.Find<IField>(f => f.Name.Equals(level, StringComparison.OrdinalIgnoreCase));
                i++;
            }

            if (field == null)
            {
                throw new Exception($"未找到字段'{fieldName}'。");
            }

            categories.AddRange(field.Categories.Select(cat => cat.FullName));
        }

        _defCache.Add(cacheKey, categories);
        return categories;
    }

    public override string FetchFieldValue(string fieldName) =>
        FirstRecord == null ? string.Empty : FirstRecord.GetFieldValue(fieldName);

    /// <summary>
    ///     样本值存储类，存储单个字段的值数据。
    /// </summary>
    public class Storage : IEnumerable<Storage>
    {
        /// <summary>
        ///     当前存储类的次级条目链表，如果此值是this，表示没有次级对象。
        /// </summary>
        private readonly Storage _childHead;

        private string _fieldValue = string.Empty;

        private Storage()
        {
            FieldName = string.Empty;
            OriginalValues = [];
            CustomFlag = 0;

            _childHead = this;
            Parent = this;
            NextStorage = this;
            PreviousStorage = this;

            CategoricalValue = new Categorical();
        }

        internal Storage(string fieldName)
        {
            FieldName = fieldName;
            OriginalValues = new List<string>();
            CustomFlag = 0;

            _childHead = new Storage { Parent = this };
            Parent = this;
            NextStorage = this;
            PreviousStorage = this;

            CategoricalValue = new Categorical();
        }

        internal Storage(string fieldName, bool isCategorical = false)
        {
            FieldName = fieldName;
            OriginalValues = new List<string>();
            IsCategorical = isCategorical;

            CategoricalValue = new Categorical();
            CustomFlag = 0;

            _childHead = new Storage { Parent = this };
            Parent = this;
            NextStorage = this;
            PreviousStorage = this;
        }


        /// <summary>
        ///     当前存储类的父级存储对象，如果此值是当前对象，表示没有父级对象。
        /// </summary>
        public Storage Parent { get; private set; }


        /// <summary>
        ///     当前存储类的下一个存储条目，只有当前存储是次级存储时，此值才有效。此值无效时，指向对象时当前对象。
        /// </summary>
        public Storage NextStorage { get; private set; }


        /// <summary>
        ///     当前存储类的上一个存储条目，只有当前存储是次级存储时，此值才有效。此值无效时，指向对象时当前对象。
        /// </summary>
        public Storage PreviousStorage { get; private set; }


        /// <summary>
        ///     获取次级存储的第一个存储对象。
        /// </summary>
        public Storage? Begin =>
            _childHead.NextStorage != _childHead ? _childHead.NextStorage : null;


        /// <summary>
        ///     获取次级存储的最后一个存储对象。
        /// </summary>
        public Storage? End =>
            _childHead.PreviousStorage != _childHead ? _childHead.PreviousStorage : null;


        /// <summary>
        ///     当前存储是否包含多层存储对象。
        /// </summary>
        public bool IsHierarchical => _childHead != this && _childHead.NextStorage != _childHead;

        /// <summary>
        ///     存储值对应的字段名。
        /// </summary>
        public string FieldName { get; set; }


        /// <summary>
        ///     当前字段的字段值字符串。
        ///     <list type="bullet">
        ///         <item>
        ///             使用此属性设置字段值时，如果值是分类值，将覆盖已有的分类值。
        ///         </item>
        ///         <item>
        ///             使用此属性获取字段值时，如果值是分类值，此值返回分类值的序列化结果。
        ///         </item>
        ///     </list>
        /// </summary>
        public string FieldValue
        {
            get
            {
                if (IsCategorical)
                {
                    return CategoricalValue.ToString();
                }

                return _fieldValue;
            }

            set
            {
                if (IsCategorical)
                {
                    CategoricalValue = new Categorical(value);
                }
                else
                {
                    _fieldValue = value;
                }
            }
        }


        /// <summary>
        ///     指示当前值是否是Categorical分类值类型。
        /// </summary>
        public bool IsCategorical { get; set; }


        /// <summary>
        ///     当前的分类值。
        /// </summary>
        public Categorical CategoricalValue { get; private set; }


        /// <summary>
        ///     字段值的原始值。
        /// </summary>
        public List<string> OriginalValues { get; }


        /// <summary>
        ///     当前字段和值的自定义标记，默认是0。
        /// </summary>
        public short CustomFlag { get; set; }


        /// <summary>
        ///     判断当前存储值是否为空。
        /// </summary>
        public bool IsEmpty => string.IsNullOrEmpty(_fieldValue) && CategoricalValue.Count == 0 && !IsHierarchical;

        public IEnumerator<Storage> GetEnumerator() => new StorageEnumerator(this);

        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();


        private void PushChild(Storage storage)
        {
            Storage last = _childHead.PreviousStorage;
            last.NextStorage = storage;
            _childHead.PreviousStorage = storage;
            storage.NextStorage = _childHead;
            storage.PreviousStorage = last;

            storage.Parent = this;
        }


        /// <summary>
        ///     向次级存储链表末尾追加一个新的存储对象，存储类型、字段名和当前类型相同。
        /// </summary>
        /// <param name="value">新添加的字段值</param>
        /// <returns>新追加的存储对象</returns>
        public Storage AddSubStorage(string value)
        {
            Storage storage = new Storage(FieldName, IsCategorical) { CustomFlag = CustomFlag };
            storage.JoinCode(value);
            PushChild(storage);
            return storage;
        }


        /// <summary>
        ///     将存储值转换为多层存储对象。转换后一定会有第一个次级存储对象。
        /// </summary>
        public void ConvertToHierarchical()
        {
            if (IsHierarchical)
            {
                return;
            }

            Storage sub = AddSubStorage(FieldValue);
            sub.CustomFlag = CustomFlag;

            _fieldValue = string.Empty;
            CategoricalValue = new Categorical();
            CustomFlag = 0;
        }


        private void ConvertToNonHierarchical()
        {
            if (!IsHierarchical)
            {
                return;
            }

            Storage n = _childHead.NextStorage;
            FieldValue = n.FieldValue;
            CustomFlag = n.CustomFlag;

            // 移除child
            _childHead.NextStorage = _childHead;
            _childHead.PreviousStorage = _childHead;
        }


        private void RemoveChild(Storage storage)
        {
            if (storage == _childHead || storage.Parent != this)
            {
                return;
            }

            Storage prev = storage.PreviousStorage;
            Storage next = storage.NextStorage;
            prev.NextStorage = next;
            next.PreviousStorage = prev;
        }


        /// <summary>
        ///     通过调用回调函数合并下级数据存储对象，只有 <see cref="IsHierarchical" /> 是true时才有效果。
        /// </summary>
        /// <param name="combineCallback">合并使用的回调，第一个参数是基础对象，第二个参数是合并进的对象，如果成功返回true，否则返回false。</param>
        public void Combine(Func<Storage, Storage, bool> combineCallback)
        {
            if (!IsHierarchical)
            {
                return;
            }

            Storage s = _childHead.NextStorage;
            while (s != _childHead)
            {
                Storage n = s.NextStorage;

                while (n != _childHead)
                {
                    if (combineCallback(s, n))
                    {
                        RemoveChild(n);
                    }

                    n = n.NextStorage;
                }

                s = s.NextStorage;
            }

            if (_childHead.NextStorage != _childHead && _childHead.NextStorage.NextStorage == _childHead)
            {
                ConvertToNonHierarchical();
            }
        }


        /// <summary>
        ///     判断当前配置的<see cref="CustomFlag" />是否包含给定值。
        /// </summary>
        /// <param name="flag">二进制Flag</param>
        /// <returns>如果<see cref="CustomFlag" />和<paramref name="flag" />按位且不是0，返回true</returns>
        public bool HasCustomFlag(short flag) => (CustomFlag & flag) != 0;


        private static bool IsCodeEmpty(string codes) =>
            string.IsNullOrEmpty(codes) || Regex.IsMatch(codes, @"\s*\{\s*\}\s*");


        /// <summary>
        ///     向分类值中添加指定的分类值，重复的分类值不会重复添加。如果指定了<paramref name="originalValues" />，
        ///     其顺序应当和<paramref name="categorical" />中的分类值顺序相对应。
        /// </summary>
        /// <param name="categorical"></param>
        /// <param name="originalValues"></param>
        /// <exception cref="Exception"></exception>
        public void JoinCode(string categorical, IList<string>? originalValues = null)
        {
            if (!IsCategorical)
            {
                throw new Exception("字段值类型不是Categorical，无法合并多个值。");
            }

            if (IsCodeEmpty(categorical))
            {
                return;
            }

            int i = 0;

            if (categorical.StartsWith("{"))
            {
                categorical = categorical.Substring(1);
            }

            if (categorical.EndsWith("}"))
            {
                categorical = categorical.Substring(0, categorical.Length - 1);
            }

            foreach (string code in categorical.Split(','))
            {
                string codeText = code.Trim();
                if (!CategoricalValue.Contains(codeText))
                {
                    CategoricalValue.Add(codeText);

                    if (originalValues != null && i < originalValues.Count)
                    {
                        OriginalValues.Add(originalValues[i]);
                    }
                    else
                    {
                        OriginalValues.Add(codeText);
                    }
                }

                ++i;
            }
        }


        private class StorageEnumerator : IEnumerator<Storage>
        {
            private readonly Storage _storage;
            private Storage? _current;

            internal StorageEnumerator(Storage storage)
            {
                _storage = storage;
                _current = storage._childHead;
            }

            public Storage Current => _current!;

            object IEnumerator.Current => Current;

            public void Dispose() => GC.SuppressFinalize(this);

            public bool MoveNext()
            {
                if (_current == null)
                {
                    return false;
                }

                _current = Current.NextStorage;
                return _current != _storage._childHead;
            }

            public void Reset() => _current = _storage._childHead;
        }
    }


    /// <summary>
    ///     关键字样本数据存储类。数据条目不强制要求绑定关键字数据。不绑定关键字数据时，使用递增的条目编号作为唯一标识符。
    /// </summary>
    public class Record
    {
        private readonly Hashtable _extraInformation;

        private readonly Dictionary<string, Storage> _fieldStorage;
        private readonly string _keyFieldName;

        public Record(string keyFieldName, string keyValue)
        {
            _fieldStorage = new Dictionary<string, Storage>();
            _keyFieldName = keyFieldName;
            KeyValue = keyValue;
            _extraInformation = new Hashtable();

            PreviousRecord = this;
            NextRecord = this;
        }

        /// <summary>
        ///     关键字值。
        /// </summary>
        public string KeyValue { get; }


        /// <summary>
        ///     上一条记录
        /// </summary>
        public Record PreviousRecord { get; internal set; }


        /// <summary>
        ///     下一条记录
        /// </summary>
        public Record NextRecord { get; internal set; }


        /// <summary>
        ///     当前已保存的字段值的迭代器。
        /// </summary>
        public IList<Storage> Values => _fieldStorage.Values.ToList();


        /// <summary>
        ///     添加额外的信息。
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void SetExtraInformation(string key, object value)
        {
            if (_extraInformation.ContainsKey(key))
            {
                _extraInformation[key] = value;
            }
            else
            {
                _extraInformation.Add(key, value);
            }
        }


        /// <summary>
        ///     尝试获取指定关键字的额外信息。
        /// </summary>
        /// <param name="key">指定关键字，区分大小写</param>
        /// <param name="info">当前存储的指定内容，如果关键字不存在，此值将为null。</param>
        /// <returns>如果关键字存在，返回true，否则，返回false。</returns>
        public bool TryGetExtraInformation(string key,
#if NET8_0_OR_GREATER
            [MaybeNullWhen(false)]
#endif
            out object? info)
        {
            info = null;

            if (!_extraInformation.ContainsKey(key))
            {
                return false;
            }

            info = _extraInformation[key];
            return info != null;
        }


        /// <summary>
        ///     获取或创建指定字段名的存储类对象，如果是新创建的存储对象，是空白对象。
        /// </summary>
        /// <param name="fieldName">字段名</param>
        /// <returns></returns>
        public Storage GetStorage(string fieldName)
        {
            string lowerName = fieldName.ToLower();

            if (_fieldStorage.TryGetValue(lowerName, out var storage))
            {
                return storage;
            }

            storage = new Storage(fieldName);
            _fieldStorage.Add(lowerName, storage);

            return storage;
        }


        /// <summary>
        ///     判断给定字段名是否已在当前存储的列表中。
        /// </summary>
        /// <param name="fieldName">给定字段名，不区分大小写</param>
        public bool HasStorage(string fieldName) => _fieldStorage.ContainsKey(fieldName.ToLower());


        /// <summary>
        ///     移除指定字段的存储值。
        /// </summary>
        /// <param name="fieldName"></param>
        public void Remove(string fieldName) => _fieldStorage.Remove(fieldName.ToLower());


        /// <summary>
        ///     移除指定的存储对象。
        /// </summary>
        /// <param name="storage"></param>
        public void Remove(Storage storage) => _fieldStorage.Remove(storage.FieldName.ToLower());


        private static void UpdateStorageValue(Storage storage, string value, IList<string>? originalValues)
        {
            if (storage.IsCategorical)
            {
                storage.JoinCode(value, originalValues);
            }
            else
            {
                storage.FieldValue = value;
            }
        }


        /// <summary>
        ///     设置给定字段的字段值。
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="fieldValue"></param>
        /// <param name="isCategorical"></param>
        /// <param name="originalValues"></param>
        /// <remarks>
        ///     <list type="bullet">
        ///         <item>
        ///             如果<paramref name="isCategorical" />是true，将给定值追加到<see cref="Storage.CategoricalValue" />分类值中。
        ///         </item>
        ///         <item>
        ///             如果<paramref name="isCategorical" />是false，将直接更新<see cref="Storage.FieldValue" />属性。
        ///         </item>
        ///     </list>
        /// </remarks>
        public void SetFieldValue(string fieldName, string fieldValue, bool isCategorical,
            IList<string>? originalValues = null)
        {
            string lowerName = fieldName.ToLower();

            if (!_fieldStorage.TryGetValue(lowerName, out var storage))
            {
                storage = new Storage(fieldName, isCategorical);
                UpdateStorageValue(storage, fieldValue, originalValues);
                _fieldStorage.Add(lowerName, storage);
            }
            else
            {
                UpdateStorageValue(storage, fieldValue, originalValues);
            }
        }


        /// <summary>
        ///     获取指定字段的存储值。
        /// </summary>
        /// <param name="fieldName">字段名，不区分大小写</param>
        /// <returns></returns>
        public string GetFieldValue(string fieldName)
        {
            return _fieldStorage.TryGetValue(fieldName.ToLower(), out var storage)
                ? storage.FieldValue
                : string.Empty;
        }


        /// <summary>
        ///     获取用于填充SampleDataTable的样本值信息列表。
        /// </summary>
        /// <returns></returns>
        public IList<SampleValueInfo> GetSampleValueInfos()
        {
            return _fieldStorage
                .Where(pair => !_keyFieldName.Equals(pair.Key, StringComparison.OrdinalIgnoreCase))
                .Select(pair =>
                    new SampleValueInfo
                    {
                        Field = pair.Value.FieldName,
                        OriginalValues = pair.Value.OriginalValues
                    }).ToList();
        }
    }

    private struct RecordEnumerator(SqlMetadataProvider provider) : IEnumerator<Record>
    {
        private readonly int _version = provider._version;
        public Record Current { get; private set; } = provider._dummyRecord;


#if NET8_0_OR_GREATER
        readonly
#endif
            object IEnumerator.Current => Current;


        private
#if NET8_0_OR_GREATER
            readonly
#endif
            void CheckVersion()
        {
            if (_version != provider._version)
            {
                throw new InvalidOperationException();
            }
        }


        public
#if NET8_0_OR_GREATER
            readonly
#endif
            void Dispose()
        {
        }

        public bool MoveNext()
        {
            CheckVersion();

            if (Current == null)
            {
                return false;
            }

            Current = Current.NextRecord;
            return Current != provider._dummyRecord;
        }

        public void Reset()
        {
            CheckVersion();
            Current = provider._dummyRecord;
        }
    }


    #region IEnumerable

    public IEnumerator<Record> GetEnumerator() => new RecordEnumerator(this);

    IEnumerator IEnumerable.GetEnumerator() => new RecordEnumerator(this);

    #endregion
}